// Copyright (C) Microsoft Corporation. All rights reserved.

using System;
using System.Text;
using System.Windows.Forms;
using System.Collections.Generic;
using System.Collections;

using System.Collections.ObjectModel;
using System.ComponentModel;

namespace Microsoft.DDSolutions.UI
{
    /// <summary>
    ///  This is a custom DataGridView Column. Allows user to select multiple items from a checked listbox.
    /// </summary>
    public class CheckBoxComboColumn : DataGridViewColumn
    {
        /// <summary>
        ///  Event handler for AddorDeletedRole events. 
        /// </summary>
        /// <param name="sender">Sender object. DataGridView in this case</param>
        /// <param name="e">AddorDeleteRole event arguments</param>

        public event EventHandler<AddedOrDeletedRoleEventArgs> AddedOrDeletedRole;

        /// <summary>
        ///   State of each Role in the listbox of this custom control. 
        /// </summary>
        public enum ItemState { Uninitialized = 0, Initial = 1, Deleted = 2, Unselected = 3, Added = 4 };

        /// <summary>
        ///    These are all the Items that the user wants to show up on the listbox.
        /// 
        /// 
        /// </summary>
        private Collection<string> mAllItems;

        private ItemState[] ItemStates;

        /// <summary>
        ///   Method to Raise AddorDeletedRole event.
        /// </summary>
        /// <param name="e">Event Arguments</param>
        public virtual void OnAddedOrDeletedRole( AddedOrDeletedRoleEventArgs e)
        {
            if (AddedOrDeletedRole != null)
            {
                AddedOrDeletedRole(this, e);
            }
        }

        public ReadOnlyCollection<string> AllItems
        {
            get
            {
                return new ReadOnlyCollection<string>(mAllItems);
            }
        }

        /// <summary>
        ///    Set the Item State of item Itm, given its ItemState value.
        /// </summary>
        /// <param name="val">Value of the ItemState</param>
        /// <param name="Item">The Item whose state is being set</param>
        public void SetItemState(ItemState stateValue,string item)
        {
            if (item == null)
                throw new ArgumentNullException("item");

            if (String.IsNullOrEmpty(item) == true)
                throw new ArgumentException("item");

            int index = mAllItems.IndexOf(item);

            if (index >= 0)
            {
                if (ItemStates == null)
                    ItemStates = new ItemState[mAllItems.Count];

                ItemStates[index] = stateValue;
            }
        }

        /// <summary>
        ///  Get the ItemState value given an Index
        /// </summary>
        /// <param name="Index">Index into the array</param>
        /// <returns>ItemState</returns>
        public ItemState GetItemState(int index)
        {
            if (ItemStates == null)
                return ItemState.Uninitialized;

            return ItemStates[index];
        }

        /// <summary>
        ///  Given the Item string get the State of that Item
        /// </summary>
        /// <param name="Item">Item value in the list</param>
        /// <returns>ItemState</returns>
        public ItemState GetItemState(string item)
        {
            if (item == null)
                throw new ArgumentNullException("item");

            if (String.IsNullOrEmpty(item) == true)
                throw new ArgumentException("item");

            int index = mAllItems.IndexOf(item);

            if (index >= 0)
            {
                return GetItemState(index);
            }
            else
            {
                return ItemState.Uninitialized;
            }
        }

        public CheckBoxComboColumn()
            : base(new CheckBoxComboCell())
        {
            mAllItems = new Collection<string>();
        }

        /// <summary>
        ///    Add an item to all items list maintained by the column
        /// </summary>
        /// <param name="item"></param>
        public void AddItem(string item)
        {
            if (item == null)
                throw new ArgumentNullException("item");

            if (String.IsNullOrEmpty(item) == true)
                throw new ArgumentException("item");
            if (mAllItems.Contains(item))
                return;
            mAllItems.Add(item);
        }

        /// <summary>
        ///    Clear all items
        /// </summary>
        /// <param name="item"></param>
        public void Clear()
        {
            mAllItems.Clear();
        }

        /// <summary>
        ///    Override CellTemplate to make sure that the type of Cell which is being set is 
        ///  of the new custom CheckBoxComboCell
        /// </summary>
        public override DataGridViewCell CellTemplate
        {
            get
            {
                return base.CellTemplate;
            }
            set
            {
                // Ensure that the cell used for the template is a CheckBoxComboCell.
                if (value != null &&
                    !value.GetType().IsAssignableFrom(typeof(CheckBoxComboCell)))
                {
                    string msg = Properties.Resources.ResourceManager.GetString("ComboCellInvalidCast", System.Globalization.CultureInfo.CurrentUICulture);
                    throw new InvalidCastException(msg);
                }
                base.CellTemplate = value;

            }
        }
    }

    /// <summary>
    ///   Event Arguments class defined for AddorDeleteRole Event.
    /// </summary>
    public class AddedOrDeletedRoleEventArgs : EventArgs
    {
        int row;
        int col;
        private CheckBoxComboColumn.ItemState state;
        private string user;
        private string displayName;
        private string role;
        public enum SystemTier {Client=0,SharePoint=1,ReportServer=2,Tfs=3} ;

        private SystemTier tier;

        public SystemTier Tier
        {
            get
            {
                return tier;
            }
            set
            {
                tier = value;
            }
        }

        public int CurrentRow
        {
            get
            {
                return row;
            }
            set
            {
                row = value;
            }
       } 

        public int CurrentCol
        {
            get
            {
                return col;
            }
            set
            {
                col = value;
            }
        }

        public CheckBoxComboColumn.ItemState ItemState
        {
            get
            {
                return state;
            }
            set
            {
                state = value;
            }
        }

        public string User
        {
            get
            {
                return user;
            }
            set
            {
                user = value;
            }
        }

        public string DisplayName
        {
            get
            {
                return displayName;
            }
            set
            {
                displayName = value;
            }
        }

        public string Role
        {
            get
            {
                return role;
            }
            set
            {
                role = value;
            }
        }
    }
    /// <summary>
    ///  Custom DataGridViewCell control. 
    /// </summary>
    public class CheckBoxComboCell : DataGridViewTextBoxCell
    {
        const int cRowHeight = 22;
        int lRowIndex;


        public CheckBoxComboCell()
            : base()
        {
        }


        /// <summary>
        ///  On user entering the cell
        /// </summary>
        /// <param name="rowIndex"></param>
        /// <param name="throughMouseClick"></param>
        protected override void OnEnter(int rowIndex, bool throughMouseClick)
        {
            base.OnEnter(rowIndex, throughMouseClick);
        }

        /// <summary>
        ///  On user leaving the cell
        /// </summary>
        /// <param name="rowIndex">Row Index in the DataGridView</param>
        /// <param name="throughMouseClick">Was the entry through mouseclick - True or false</param>
        protected override void OnLeave(int rowIndex, bool throughMouseClick)
        {
            this.DataGridView.Rows[rowIndex].Height = cRowHeight;
            CheckBoxComboColumn parentColumn = (CheckBoxComboColumn)this.DataGridView.Columns[this.DataGridView.CurrentCell.ColumnIndex];

            /// Identify if the user has Added or Deleted any items from the list box by selecting or unselecting the items.
            /// If so get all the relevant context information and add it to AddorDeleteRoleEventArgs and raise the event
            /// AddedorDeletedRole by calling parentColumn.OnAddedOrDeletedRole(e);
            for (int Index = 0; Index < parentColumn.AllItems.Count; Index++)
            {
                if (parentColumn.GetItemState(Index) == CheckBoxComboColumn.ItemState.Added ||
                    parentColumn.GetItemState(Index) == CheckBoxComboColumn.ItemState.Deleted)
                {
                    AddedOrDeletedRoleEventArgs e = new AddedOrDeletedRoleEventArgs();

                    e.CurrentRow = this.DataGridView.CurrentCell.RowIndex;
                    e.CurrentCol = this.DataGridView.CurrentCell.ColumnIndex;

                    if (this.DataGridView.Rows[e.CurrentRow].Cells["User"] != null)
                    {
                        e.User = this.DataGridView.Rows[e.CurrentRow].Cells["User"].Value.ToString();
                        e.DisplayName = this.DataGridView.Rows[e.CurrentRow].Cells["DisplayName"].Value.ToString();
                        e.Role = parentColumn.AllItems[Index].ToString();
                        e.ItemState = parentColumn.GetItemState(Index);

                        if (this.DataGridView.CurrentCell.ColumnIndex == 3)
                            e.Tier = AddedOrDeletedRoleEventArgs.SystemTier.Tfs;
                        else if (this.DataGridView.CurrentCell.ColumnIndex == 4)
                            e.Tier = AddedOrDeletedRoleEventArgs.SystemTier.SharePoint;
                        else if (this.DataGridView.CurrentCell.ColumnIndex == 5)
                            e.Tier = AddedOrDeletedRoleEventArgs.SystemTier.ReportServer;

                        parentColumn.OnAddedOrDeletedRole(e);

                        if(parentColumn.GetItemState(Index) == CheckBoxComboColumn.ItemState.Deleted)
                            parentColumn.SetItemState(CheckBoxComboColumn.ItemState.Unselected, parentColumn.AllItems[Index]);
                        else if(parentColumn.GetItemState(Index) == CheckBoxComboColumn.ItemState.Added)
                            parentColumn.SetItemState(CheckBoxComboColumn.ItemState.Initial, parentColumn.AllItems[Index]);
                    }
                }
            }

        }


        public override void InitializeEditingControl(int rowIndex, object
            initialFormattedValue, DataGridViewCellStyle dataGridViewCellStyle)
        {
            try
            {
                if (initialFormattedValue == null)
                    initialFormattedValue = string.Empty;
                // Set the value of the editing control to the current cell value.
                base.InitializeEditingControl(rowIndex, initialFormattedValue,
                    dataGridViewCellStyle);

        CheckBoxComboEditingControl ctl = (CheckBoxComboEditingControl) this.DataGridView.EditingControl;

                ctl.Height = 200;
                ctl.EditingControlFormattedValue = initialFormattedValue;

                this.DataGridView.Rows[rowIndex].Height = cRowHeight;

                this.lRowIndex = rowIndex;
            }
            catch (Exception)
            {

            }
        }


        /// <summary>
        /// Returns the Type of the EditControl.
        /// </summary>
        public override Type EditType
        {
            get
            {
                this.DataGridView.Rows[lRowIndex].Height = cRowHeight;
                return typeof(CheckBoxComboEditingControl);
            }
        }

        /// <summary>
        ///  Return the Value Type of the cell.
        /// </summary>
        public override Type ValueType
        {
            get
            {
                this.DataGridView.Rows[lRowIndex].Height = cRowHeight;
                return typeof(string);
            }
        }

        /// <summary>
        ///   Returns the default New Row Value.
        /// </summary>
        public override object DefaultNewRowValue
        {
            get
            {
                return string.Empty;
            }
        }
    }
    /// <summary>
    ///   Custom Edit Control for the DataGridView cell.
    /// </summary>
class CheckBoxComboEditingControl : CheckedListBox , IDataGridViewEditingControl
    {
        DataGridView dataGridView;
        private bool valueChanged;
        int lRowIndex;
        private bool preserveStates;
        const int cRowHeight = 22;
        /// <summary>
        ///   In order to notify to this object to preserver the State of items in the parent Column.
        /// </summary>
        public bool PreserveItemStates
        {
            get
            {
                return preserveStates;
            }
            set
            {
                preserveStates = value;
            }
        }

        public CheckBoxComboEditingControl()
        {
            this.Visible = true;
            this.CheckOnClick = true;

        }

        // Implements the IDataGridViewEditingControl.EditingControlFormattedValue 
        // property.
        public object EditingControlFormattedValue
        {
            get
            {
                 string sValue = "";
                StringBuilder sb = new StringBuilder();
            foreach(object itemChecked in this.CheckedItems)
                {
                    sb.Append(itemChecked.ToString());
                    sb.Append(";");
                }

                sValue = sb.ToString();

                int pos = sValue.LastIndexOf(';');
                if (pos > 0 && pos == sValue.Length - 1)
                    sValue = sValue.Remove(pos, 1);

                return sValue;
            }
            set
            {
                String newValue = value as String;
                if (String.IsNullOrEmpty(newValue) == false)
                {
                    string delimiter = ";";


                    string[] itms = newValue.Split(delimiter.ToCharArray());

                    this.Items.Clear();

                    foreach (string itemstr in itms)
                    {
                        this.Items.Add(itemstr, true);
                    }
                }
                else
                    this.Items.Clear();
            }
        }

        // Implements the 
        // IDataGridViewEditingControl.GetEditingControlFormattedValue method.
        public object GetEditingControlFormattedValue(
            DataGridViewDataErrorContexts context)
        {
            return EditingControlFormattedValue;
        }

        // Implements the 
        // IDataGridViewEditingControl.ApplyCellStyleToEditingControl method.
        public void ApplyCellStyleToEditingControl(
            DataGridViewCellStyle dataGridViewCellStyle)
        {
            if (dataGridViewCellStyle == null) throw new ArgumentNullException("dataGridViewCellStyle");
            this.Font = dataGridViewCellStyle.Font;
            this.dataGridView.Rows[lRowIndex].Height = Items.Count * this.dataGridView.Rows[lRowIndex].Height;
        }

        // Implements the IDataGridViewEditingControl.EditingControlRowIndex 
        // property.
        public int EditingControlRowIndex
        {
            get
            {
                return lRowIndex;
            }
            set
            {
                lRowIndex = value;
            }
        }

        // Implements the IDataGridViewEditingControl.EditingControlWantsInputKey 
        // method.
        public bool EditingControlWantsInputKey(
            Keys key, bool dataGridViewWantsInputKey)
        {
            // Let the CheckedListBox handle the keys listed.
            switch (key & Keys.KeyCode)
            {
                case Keys.Left:
                case Keys.Up:
                case Keys.Down:
                case Keys.Right:
                case Keys.Home:
                case Keys.End:
                case Keys.PageDown:
                case Keys.PageUp:
                    return true;
                default:
                    return false;
            }
        }

        // Implements the IDataGridViewEditingControl.PrepareEditingControlForEdit 
        // method.
        public void PrepareEditingControlForEdit(bool selectAll)
        {
            CheckBoxComboColumn parentColumn = (CheckBoxComboColumn) this.dataGridView.Columns[this.dataGridView.CurrentCell.ColumnIndex];

        int index=0;


            foreach (string itm in parentColumn.AllItems)
            {
                if (!this.Items.Contains(itm))
                {
                    this.Items.Add(itm, false);
                    if (parentColumn.GetItemState(itm) == CheckBoxComboColumn.ItemState.Uninitialized)
                        parentColumn.SetItemState(CheckBoxComboColumn.ItemState.Unselected, itm);
                }

                index++;
            }

            this.dataGridView.Rows[lRowIndex].Height = Items.Count * cRowHeight;

        }

        // Implements the IDataGridViewEditingControl
        // .RepositionEditingControlOnValueChange property.
        public bool RepositionEditingControlOnValueChange
        {
            get
            {
                return false;
            }
        }

        // Implements the IDataGridViewEditingControl
        // .EditingControlDataGridView property.
        public DataGridView EditingControlDataGridView
        {
            get
            {
                return dataGridView;
            }
            set
            {
                dataGridView = value;
            }
        }

        // Implements the IDataGridViewEditingControl
        // .EditingControlValueChanged property.
        public bool EditingControlValueChanged
        {
            get
            {
                this.dataGridView.Rows[lRowIndex].Height = cRowHeight;
                return valueChanged;
            }
            set
            {
                valueChanged = value;
            }
        }

        // Implements the IDataGridViewEditingControl
        // .EditingPanelCursor property.
        public Cursor EditingPanelCursor
        {
            get
            {
                return base.Cursor;
            }
        }

        /// <summary>
        ///  When the user Checks or Unchecks an Item in the list box the following function is invoked.
        /// </summary>
        /// <param name="ice">This argument has context information like index of the item in the list</param>
    protected override void  OnItemCheck(ItemCheckEventArgs ice)
        {
            base.OnItemCheck(ice);
            int cindex = ice.Index;


        CheckBoxComboColumn parentColumn = (CheckBoxComboColumn)this.dataGridView.Columns[this.dataGridView.CurrentCell.ColumnIndex];
            string itm = this.Items[cindex].ToString();

            {
                if (ice.NewValue == ice.CurrentValue)
                    return;

                if (ice.NewValue == CheckState.Checked)
                {
                    if (parentColumn.GetItemState(itm) == CheckBoxComboColumn.ItemState.Uninitialized)
                        parentColumn.SetItemState(CheckBoxComboColumn.ItemState.Initial, itm);
                    else if (parentColumn.GetItemState(itm) == CheckBoxComboColumn.ItemState.Unselected)
                        parentColumn.SetItemState(CheckBoxComboColumn.ItemState.Added, itm);
                    else if (parentColumn.GetItemState(itm) == CheckBoxComboColumn.ItemState.Deleted)
                        parentColumn.SetItemState(CheckBoxComboColumn.ItemState.Initial, itm);
                }
                else if (ice.NewValue == CheckState.Unchecked)
                {
                    if (parentColumn.GetItemState(itm) == CheckBoxComboColumn.ItemState.Initial)
                        parentColumn.SetItemState(CheckBoxComboColumn.ItemState.Deleted, itm);
                    else if (parentColumn.GetItemState(itm) == CheckBoxComboColumn.ItemState.Added)
                        parentColumn.SetItemState(CheckBoxComboColumn.ItemState.Unselected, itm);
                }
            }


            valueChanged = true;
            this.EditingControlDataGridView.NotifyCurrentCellDirty(true);
        }

    }

}


